package com.mazaiting.classfile.attr.entity;

import com.mazaiting.classfile.ClassReader;
import com.mazaiting.classfile.constant.ConstantPool;

import java.util.Arrays;

/**
 * 节点值
 *
 * @author mazaiting
 * @since 2021/8/13
 */
public abstract class ElementValueEntity {
    /**
     * 常量池
     */
    protected final ConstantPool pool;
    /**
     * 标识 无符号 u1
     */
    protected final short tag;

    protected ElementValueEntity(short tag, ConstantPool pool) {
        this.tag = tag;
        this.pool = pool;
    }

    /**
     * 读取具体信息
     * @param reader 类读取器
     */
    protected abstract void readInfo(ClassReader reader);

    /**
     * 读取节点值
     * @param reader 读取器
     * @param pool 常量池
     * @return 节点
     */
    public static ElementValueEntity read(ClassReader reader, ConstantPool pool) {
        short tag = reader.readU1ToUnsignedByte();
        ElementValueEntity value;
        switch (tag) {
            case 'B':// byte
            case 'C':// char
            case 'D':// double
            case 'F':// float
            case 'I':// int
            case 'J':// long
            case 'S':// short
            case 'Z':// boolean
            case 's':// String
                value = new ConstValueElementEntity(tag, pool);
                break;
            case 'e':// Enum type
                value = new EnumConstValueElementEntity(tag, pool);
                break;
            case 'c':// Class
                value = new ClassInfoElementEntity(tag, pool);
                break;
            case '@':// Annotation type
                value = new AnnotationValueElementEntity(tag, pool);
                break;
            case '[':// Array type
                value = new ArrayValueElementEntity(tag, pool);
                break;
            default:
                throw new RuntimeException("unknown tag: " + tag);
        }
        value.readInfo(reader);
        return value;
    }

    private static class ConstValueElementEntity extends ElementValueEntity {
        /**
         * 常量索引 无符号 u2
         */
        private int constValueIndex;

        protected ConstValueElementEntity(short tag, ConstantPool pool) {
            super(tag, pool);
        }

        @Override
        protected void readInfo(ClassReader reader) {
            this.constValueIndex = reader.readU2ToUnsignedShort();
        }

        @Override
        public String toString() {
            return "ConstValueElement{" +
                    "tag=" + tag +
                    ", constValueIndex=" + constValueIndex +
                    '}';
        }
    }

    private static class EnumConstValueElementEntity extends ElementValueEntity {
        /**
         * 类型名索引 无符号 u2
         */
        private int typeNameIndex;
        /**
         * 常量名索引 无符号 u2
         */
        private int constNameIndex;

        protected EnumConstValueElementEntity(short tag, ConstantPool pool) {
            super(tag, pool);
        }

        @Override
        protected void readInfo(ClassReader reader) {
            this.typeNameIndex = reader.readU2ToUnsignedShort();
            this.constNameIndex = reader.readU2ToUnsignedShort();
        }

        @Override
        public String toString() {
            return "EnumConstValueElement{" +
                    "tag=" + tag +
                    ", typeNameIndex=" + typeNameIndex +
                    ", constNameIndex=" + constNameIndex +
                    '}';
        }
    }

    private static class ClassInfoElementEntity extends ElementValueEntity {
        /**
         * 类信息索引 无符号 u2
         */
        private int classInfoIndex;

        protected ClassInfoElementEntity(short tag, ConstantPool pool) {
            super(tag, pool);
        }

        @Override
        protected void readInfo(ClassReader reader) {
            this.classInfoIndex = reader.readU2ToUnsignedShort();
        }

        @Override
        public String toString() {
            return "ClassInfoElement{" +
                    "tag=" + tag +
                    ", classInfoIndex=" + classInfoIndex +
                    '}';
        }
    }

    private static class AnnotationValueElementEntity extends ElementValueEntity {
        /**
         * 注解值
         */
        private AnnotationsEntity annotationValue;

        protected AnnotationValueElementEntity(short tag, ConstantPool pool) {
            super(tag, pool);
        }

        @Override
        protected void readInfo(ClassReader reader) {
            this.annotationValue = new AnnotationsEntity(reader, pool);
        }

        @Override
        public String toString() {
            return "AnnotationValueElement{" +
                    "tag=" + tag +
                    ", annotationValue=" + annotationValue +
                    '}';
        }
    }

    private static class ArrayValueElementEntity extends ElementValueEntity {
        /**
         * 节点值数量 无符号 u2
         */
        private int numValues;
        /**
         * 节点值数组
         */
        private ElementValueEntity[] elementValueEntities;

        protected ArrayValueElementEntity(short tag, ConstantPool pool) {
            super(tag, pool);
        }

        @Override
        protected void readInfo(ClassReader reader) {
            this.numValues = reader.readU2ToUnsignedShort();
            this.elementValueEntities = new ElementValueEntity[numValues];
            for (int i = 0; i < numValues; i++) {
                this.elementValueEntities[i] = ElementValueEntity.read(reader, pool);
            }
        }

        @Override
        public String toString() {
            return "ArrayValueElement{" +
                    "tag=" + tag +
                    ", numValues=" + numValues +
                    ", elementValues=" + Arrays.toString(elementValueEntities) +
                    '}';
        }
    }
}


















